﻿using Blm.PgsqlDriver.Helpers;
using Blm.Utils.Extensions;
using Blm.Utils.Utility;
using Language.Resource;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VisionCloud.Core.Model.Ms;
using VisionCloud.Core.Model.Sys;
using VisionCloud.Domain.Common;
using VisionCloud.Domain.DtoModel.Sys;
using VisionCloud.Domain.Repository.Interface.Ms;
using VisionCloud.Service.Sys;
using VisionCloud.Utility;
using VisionCloud.Utility.Extensions;

namespace VisionCloud.Service.Ms
{
    public class UserToProjectMessageService
    {
        public IMsProjectRepository IMsProjectRepository { get; set; }

        public IStringLocalizer<ServiceResource> Localizer { get; set; }

        public SmsService smsService { get; set; }

        public MsProjectEditLogService MsProjectEditLogService { set; get; }

        /// <summary>
        /// 项目状态是否可以发布短信
        /// </summary>
        /// <param name="project">当前项目</param>
        /// <returns></returns>
        private bool IsCanSendMessageByProjectStatus(MsProject project)
        {
            //如果项目没有发布过，不需要短信通知用户
            return project.PubliceDate.HasValue;
        }

        private bool IsSendAddMessageByProjectStatus(MsProject project)
        {
            return project.IsCanPull;
        }

        private async Task SaveUserToProjectSendMesssage(List<MsUserToProject> entityList)
        {
            if (entityList == null || entityList.Count() < 1)
                return;
            string baseSql = @"update ""MsUserToProject"" set  ""IsSendMessage"" = {0} where ""YunUserGuid"" = '{1}' and ""YunProjectGuid"" = '{2}';";
            StringBuilder sb = new StringBuilder();
            entityList.ForEach(item =>
            {
                var itemSql = string.Format(baseSql, item.IsSendMessage, item.YunUserGuid, item.YunProjectGuid);
                sb.Append(itemSql);
            });

            await PgSqlHelper.ExecuteNonQueryAsync(CommandType.Text, sb.ToString());
        }

        /// <summary>
        /// 发送消息到这个用户
        /// </summary>
        /// <param name="ip">当前用户的ip</param>
        /// <param name="phoneNumber">手机号</param>
        /// <param name="message">消息内容</param>
        /// <returns></returns>
        private void SendMessageToThePhone(string ip, string phoneNumber, string message)
        {
            //如果不是手机号码
            if (!RegChecker.IsMobilePhone(phoneNumber))
                return;

            Task.Run(async () =>
            {
                Guid guid = Guid.NewGuid();
                Logger.Info($"currentUser：{OperatorProvider.Get()?.Id.ToString()}");
                Logger.Info($"{guid} SendMessageToThePhone：begin{ip}:{phoneNumber.SetSensitive()}:{message}");
                await smsService.SendSms(ip, phoneNumber, message);
                Logger.Info($"{guid} SendMessageToThePhone：end");
            });
        }

        internal bool IsNeedToSendDeleteMessage(MsUserToProject msUserToProject)
        {
            return msUserToProject.IsSendMessage;
        }

        internal bool DBSendStatusForNewAdd(bool isSendedToUser, List<MsUserToProject> oldUserToProjectInDB, Guid currentProjectGuid)
        {
            var oldMessageInDB = oldUserToProjectInDB
                                   .Where(i => i.YunProjectGuid == currentProjectGuid)
                                   .Select(i => i)
                                   .FirstOrDefault();
            return (isSendedToUser
                       ? true
                       :
                       (oldMessageInDB != null
                                                ?
                                                oldMessageInDB.IsSendMessage
                                                :
                                                 true
                                                ));
        }

        /// <summary>
        /// 获取新增加和新删除的Guid
        /// </summary>
        /// <param name="newList">最新列表</param>
        /// <param name="oldList">最旧列表</param>
        /// <returns></returns>
        internal (List<Guid> newAdd, List<Guid> newDelete, List<Guid> allList, bool isHaveAdd, bool isHaveDelete) GetNewAddOrNewDeleteAllList(List<Guid> newList, List<Guid> oldList)
        {
            List<Guid> newAddList, newDeleteList, allList;
            bool isHaveAdd, isHaveDelete;
            allList = newList
             .Select(i => i)
             .Union(oldList.Select(i => i)
             ).Distinct().ToList();
            newAddList = allList.Except(oldList).ToList();
            newDeleteList = allList.Except(newList).ToList();
            isHaveAdd = (newAddList != null && newAddList.Count() > 0);
            isHaveDelete = (newDeleteList != null && newDeleteList.Count() > 0);
            //(newAddList != null && newAddList.Count() > 0)(newDeleteList != null && newDeleteList.Count() > 0)
            return (newAddList, newDeleteList, allList, isHaveAdd, isHaveDelete);
        }

        /// <summary>
        /// 用户分配项目发送消息逻辑方法
        /// </summary>
        /// <param name="oldUserInProjectList">关联项目历史用户</param>
        /// <param name="newUserInProjectList">新关联用户</param>
        /// <param name="ip">用户IP</param>
        /// <param name="userInfos">用户信息</param>
        /// <param name="project">项目信息</param>
        internal async Task SetUserToProjectSendMessageLogic(
            List<MsUserToProject> oldUserInProjectList,
            IEnumerable<MsUserToProject> newUserInProjectList,
            string ip,
            List<SysUser> userInfos,
            MsProject project)
        {
            try
            {
                if (!IsCanSendMessageByProjectStatus(project)) return;
                var addAndDeleteAndAll = GetNewAddOrNewDeleteAllList(
                    newUserInProjectList.Select(i => i.YunUserGuid).ToList(),
                    oldUserInProjectList.Select(i => i.YunUserGuid).ToList()
                    );
                SysUser currentUser;
                string messageContent;
                if (IsSendAddMessageByProjectStatus(project))
                {
                    foreach (Guid userGuid in addAndDeleteAndAll.newAdd)
                    {
                        currentUser = userInfos.Where(i => i.YunUserGuid == userGuid).FirstOrDefault();
                        messageContent = string.Format(Localizer["YB0208"].Value, currentUser.Name, project.Name);
                        SendMessageToThePhone(ip, currentUser.PhoneNumber, messageContent);
                    }
                    await SaveUserToProjectSendMesssage(
                        (from c in addAndDeleteAndAll.newAdd
                         select new MsUserToProject
                         {
                             YunUserGuid = c,
                             YunProjectGuid = project.ProjectId,
                             IsSendMessage = true
                         }).ToList()
                        );
                }
                foreach (var deleteUserItem in addAndDeleteAndAll.newDelete)
                {
                    var currentUToP = oldUserInProjectList.Where(i => i.YunUserGuid == deleteUserItem).FirstOrDefault();
                    if (IsNeedToSendDeleteMessage(currentUToP))
                    {
                        currentUser = userInfos.Where(i => i.YunUserGuid == deleteUserItem).FirstOrDefault();
                        messageContent = string.Format(Localizer["YB0207"].Value, currentUser.Name, project.Name);
                        SendMessageToThePhone(ip, currentUser.PhoneNumber, messageContent);
                    }
                }

                #region 添加分配操作日志

                Guid createBy = newUserInProjectList.FirstOrDefault() == null ? Guid.Empty : newUserInProjectList.FirstOrDefault().CreatedBy;
                await MsProjectEditLogService.AddChangeProjectUsersLog(addAndDeleteAndAll.newAdd, addAndDeleteAndAll.newDelete, userInfos, project, createBy);

                #endregion 添加分配操作日志
            }
            catch (Exception ex)
            {
                Logger.Error("发送短信失败：" + Newtonsoft.Json.JsonConvert.SerializeObject(newUserInProjectList), ex);
            }
        }

        /// <summary>
        /// 获取项目组名称
        /// </summary>
        /// <param name="projectList">项目列表</param>
        /// <returns></returns>
        private string GetProjectNamesByArray(List<MsProject> projectList)
        {
            string projectNames = string.Empty;
            if (projectList.Count() > 0)
            {
                projectList.ForEach(prj =>
                {
                    projectNames = projectNames + "【" + prj.Name + "】" + "项目" + ",";
                });
                projectNames = projectNames.Remove(projectNames.Length - 1, 1);
            }
            return projectNames;
        }

        /// <summary>
        /// 通过模板获取消息
        /// </summary>
        /// <param name="template">模板</param>
        /// <param name="userName">用户名称</param>
        /// <param name="projectName">项目名称</param>
        /// <returns></returns>
        private string GetMessageInfo(string template, string userName, string projectName)
        {
            return template.Replace("{userName}", userName).Replace("{ProjectName}", projectName);
        }

        /// <summary>
        /// 保存用户信息发送消息
        /// </summary>
        /// <param name="oldUserProjects">旧用户项目关系</param>
        /// <param name="model">用户信息</param>
        /// <param name="newProjectIDs">新项目用户关系</param>
        /// <param name="allProject"></param>
        internal async Task SaveUserSendMessage(List<MsUserToProject> oldUserProjects, SysUserDto model, Guid[] newProjectIDs, List<MsProject> allProject)
        {
            try
            {
                var addAndDeleteEntity = GetNewAddOrNewDeleteAllList(newProjectIDs.ToList(), oldUserProjects.Select(i => i.YunProjectGuid).ToList());
                var allProjectInfoInDB = allProject;
                string phoneMessageContent = string.Empty;
                if (addAndDeleteEntity.isHaveAdd)
                {
                    var needToAddListProject = allProjectInfoInDB.Where(
                         i => addAndDeleteEntity.newAdd.Contains(i.ProjectId)
                           && IsCanSendMessageByProjectStatus(i)
                           && IsSendAddMessageByProjectStatus(i)
                            ).ToList();
                    await AddUserSendMessageBatchBase(needToAddListProject, addAndDeleteEntity.newAdd, oldUserProjects, model.IP, model.PhoneNumber, model.Name, model.UserId);
                }
                if (addAndDeleteEntity.isHaveDelete)
                {
                    var needToDeleteListProject = allProjectInfoInDB.Where(
                       i => addAndDeleteEntity.newDelete.Contains(i.ProjectId)
                         && IsNeedToSendDeleteMessage(
                             oldUserProjects.Where(mp => mp.YunProjectGuid == i.ProjectId).FirstOrDefault()
                             )
                          ).ToList();
                    if (needToDeleteListProject.Count() > 0)
                    {
                        phoneMessageContent = GetProjectNamesByArray(needToDeleteListProject.ToList());
                        if (!string.IsNullOrEmpty(phoneMessageContent))
                        {
                            string msg = string.Format(Localizer["YB0206"].Value, model.Name, phoneMessageContent);
                            SendMessageToThePhone(model.IP, model.PhoneNumber, msg);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Error("发送短信失败：UserID" + model.YunUserGuid + ";ProjectID" + Newtonsoft.Json.JsonConvert.SerializeObject(oldUserProjects) + Newtonsoft.Json.JsonConvert.SerializeObject(newProjectIDs), ex);
            }
        }

        private async Task AddUserSendMessageBatchBase(
           List<MsProject> canSendToUserProjectList,
           List<Guid> allNeedToSendUserProjectGuidList,
           List<MsUserToProject> oldUserToProjectInfoListInDB, string ip, string phoneNumber, string userName, Guid userGuid)
        {
            if (canSendToUserProjectList.Count() > 0)
            {
                string phoneMessageContent = GetProjectNamesByArray(canSendToUserProjectList);
                if (!string.IsNullOrEmpty(phoneMessageContent))
                {
                    string msg = string.Format(Localizer["YB0205"].Value, userName, phoneMessageContent);
                    SendMessageToThePhone(ip, phoneNumber, msg);
                    //已经发送短信的标注为发送,没有发送的去之前的
                    await SaveUserToProjectSendMesssage(
                       (from c in canSendToUserProjectList
                        select new MsUserToProject
                        {
                            YunUserGuid = userGuid,
                            YunProjectGuid = c.ProjectId,
                            IsSendMessage = DBSendStatusForNewAdd(allNeedToSendUserProjectGuidList.Any(i => i == c.ProjectId), oldUserToProjectInfoListInDB, c.ProjectId)
                        }).ToList()
                   );
                }
            }
        }

        /// <summary>
        /// 增加用户信息的时候发短信
        /// </summary>
        /// <param name="ip">当前登录用户客户端IP</param>
        /// <param name="projectIds">关联的项目ID</param>
        /// <param name="userName">用户名称</param>
        /// <param name="phoneNumber">手机号</param>
        /// <param name="userGuid">用户ID</param>
        /// <returns></returns>
        internal async Task AddUserSendMessage(string ip, List<Guid> projectIds, string userName, string phoneNumber, Guid userGuid)
        {
            try
            {
                var allNeedToSendUserProject = await IMsProjectRepository.WhereAsync(i => projectIds.Contains(i.ProjectId)).ConfigureAwait(false);
                var canSendProjectList = allNeedToSendUserProject.Where(i => IsCanSendMessageByProjectStatus(i) && IsSendAddMessageByProjectStatus(i)).ToList();
                Logger.Info("导入/添加用户操作：项目数：" + canSendProjectList.Count);
                await AddUserSendMessageBatchBase(canSendProjectList, allNeedToSendUserProject.Select(i => i.ProjectId).ToList(), new List<MsUserToProject>(), ip, phoneNumber, userName, userGuid);
            }
            catch (Exception ex)
            {
                Logger.Error("发送短信失败：UserID" + userGuid + ";ProjectID" + Newtonsoft.Json.JsonConvert.SerializeObject(projectIds), ex);
            }
        }

        internal async Task PubliceProject(List<SysUser> allNeedToSendMessageUser, string ip, MsProject project, List<MsUserToProject> uTP, bool isFirstPublice, string workOrderMsg = "")
        {
            try
            {
                foreach (var user in allNeedToSendMessageUser)
                {
                    //如果
                    if (isFirstPublice)
                    {
                        SendMessageToThePhone(ip, user.PhoneNumber, string.Format(Localizer["YB0208"].Value, user.Name, project.Name) + workOrderMsg);
                    }
                    else
                    {
                        if (uTP.Any(i => i.YunUserGuid == user.YunUserGuid && i.IsSendMessage == false))
                        {
                            SendMessageToThePhone(ip, user.PhoneNumber, string.Format(Localizer["YB0208"].Value, user.Name, project.Name) + workOrderMsg);
                        }
                        else
                        {
                            SendMessageToThePhone(ip, user.PhoneNumber, string.Format(Localizer["YB0209"].Value, user.Name, project.Name) + workOrderMsg);
                        }
                    }
                }
                await SaveUserToProjectSendMesssage(
                          (from c in allNeedToSendMessageUser
                           select new MsUserToProject
                           {
                               YunUserGuid = c.YunUserGuid,
                               YunProjectGuid = project.ProjectId,
                               IsSendMessage = true//,
                           }).ToList()
                        );
            }
            catch (Exception ex)
            {
                Logger.Error("发送短信失败：" + Newtonsoft.Json.JsonConvert.SerializeObject(uTP), ex);
            }
        }
    }
}